package com.hemerasolutions.v2trainer.dao;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.springframework.stereotype.Repository;

import com.hemerasolutions.v2trainer.dao.interfaces.AthleteDaoInterface;
import com.hemerasolutions.v2trainer.model.modality.Modality;
import com.hemerasolutions.v2trainer.model.modality.Modality_;
import com.hemerasolutions.v2trainer.model.schedule.Schedule;
import com.hemerasolutions.v2trainer.model.schedule.Schedule_;
import com.hemerasolutions.v2trainer.model.training.TrainingType;
import com.hemerasolutions.v2trainer.model.users.Academy;
import com.hemerasolutions.v2trainer.model.users.Athlete;
import com.hemerasolutions.v2trainer.model.users.Athlete_;
import com.hemerasolutions.v2trainer.model.users.PersonalTrainer;
import com.hemerasolutions.v2trainer.model.users.User;
import com.hemerasolutions.v2trainer.model.users.User_;


@Repository(value = "athleteDao")
public class AthleteDao extends BaseDao<Athlete> implements AthleteDaoInterface{
	private static final long serialVersionUID = 1L;

	@Override
	public List<Athlete> search( Map<String, Object> fields) {

		List<Predicate> predicateList = new ArrayList<Predicate>();

		CriteriaBuilder cb = this.getEntityManager().getCriteriaBuilder();

		CriteriaQuery<Athlete> cq  = cb.createQuery(Athlete.class);
		
		Root<Athlete> athlete = cq.from(Athlete.class);

		Join<Athlete,Schedule> joinSchedule = null;

		Join<Schedule,Modality> joinModality = null;

		
		Predicate pred;

		Join<Athlete,User> junction = athlete.join(Athlete_.user,JoinType.LEFT); 

		
	    for (Map.Entry<String,Object> line : fields.entrySet()) {
	    	
	    	if(line.getKey().toString() == "email" ){

	    		pred = cb.like(cb.upper(junction.<String>get(line.getKey().toString())), 
	    								"%"+line.getValue().toString().toUpperCase()+"%");
	            predicateList.add(pred);    		
	    	}

	    	
	    	if(line.getKey().toString() == "academy"){
	    		pred = cb.isMember( (Academy)line.getValue(), athlete.get(Athlete_.academys) );
                predicateList.add(pred);    		

	    	}
	    	
	    	if(line.getKey().toString() == "personalTrainer"){
	    		pred = cb.isMember( (PersonalTrainer)line.getValue(), athlete.get(Athlete_.personalTrainers) );
                predicateList.add(pred);    		

	    	}
	    	
	    	if( line.getKey().toString() == "firstName" 	 	||
	    			line.getKey().toString() == "lastName" 		||
   					line.getKey().toString() == "cpf" 			||
	    			line.getKey().toString() == "city" 	 		||
					line.getKey().toString() == "address" 		||
					line.getKey().toString() == "postalCode" 	 ){
	    		
	    		pred = cb.like(cb.upper(athlete.<String>get(line.getKey().toString())), 
        								"%"+line.getValue().toString().toUpperCase()+"%");
                predicateList.add(pred);    		
        	}	    	


	    	if(line.getKey().toString() == "modalitys"){

	    		if(joinSchedule == null){
	    			joinSchedule = athlete.join(Athlete_.schedules,JoinType.LEFT);
	    		}
	    		
	    	    @SuppressWarnings("unchecked")
	    		List<Modality> modalitys =  (List<Modality>)line.getValue();
	    		Expression<Modality> mod = joinSchedule.get(Schedule_.modality);
	    		pred = mod.in(modalitys);
                predicateList.add(pred);    
	    		
	    	}

	    	if(line.getKey().toString() == "trainingTypes"){

	    		if(joinSchedule == null){
	    			joinSchedule = athlete.join(Athlete_.schedules,JoinType.LEFT);
	    		}
	    			    		
	    		joinModality = joinSchedule.join(Schedule_.modality,JoinType.LEFT);
	    		
	    	    @SuppressWarnings("unchecked")
	    		List<TrainingType> tts =  (List<TrainingType>)line.getValue();
	    		Expression<TrainingType> tt = joinModality.get(Modality_.trainingType);
	    		pred = tt.in(tts);
                predicateList.add(pred);    
	    		
	    		
	    	}
	    	
	    	
	    	if( line.getKey().toString() == "begBirthday" ){ 
	    		pred = cb.greaterThanOrEqualTo(athlete.<Date>get(Athlete_.birthday), (Date)line.getValue());
	    		predicateList.add(pred);    		
	    	}

	    	if( line.getKey().toString() == "endBirthDay" ){ 
	    		pred = cb.greaterThanOrEqualTo(athlete.<Date>get(Athlete_.birthday), (Date)line.getValue());
	    		predicateList.add(pred);    		
	    	}
	    	
	    	if( line.getKey().toString() == "begCreatedAt" ){ 
	    		pred = cb.greaterThanOrEqualTo(junction.<Date>get(User_.createdAt), (Date)line.getValue());
	    		predicateList.add(pred);    		
	    	}
	    	
	    	if( line.getKey().toString() == "endCreatedAt" ){ 
	    		pred = cb.lessThanOrEqualTo(junction.<Date>get(User_.createdAt), this.endDayDateHour((Date)line.getValue()));
	    		predicateList.add(pred);    		
	    	}
	    	
	    	if( line.getKey().toString() == "begChangedAt" ){ 
	    		pred = cb.greaterThanOrEqualTo(junction.<Date>get(User_.lastChange), (Date)line.getValue());
	    		predicateList.add(pred);    		
	    	}

	    	if( line.getKey().toString() == "endChangedAt" ){ 
	    		pred = cb.lessThanOrEqualTo(junction.<Date>get(User_.lastChange), this.endDayDateHour((Date)line.getValue()));
	    		predicateList.add(pred);    		
	    	}

	    	if( line.getKey().toString() == "begExpireOn" ){ 
	    		pred = cb.greaterThanOrEqualTo(junction.<Date>get(User_.expireOn), (Date)line.getValue());
	    		predicateList.add(pred);    		
	    	}

	    	if( line.getKey().toString() == "endExpireOn" ){ 
	    		pred = cb.lessThanOrEqualTo(junction.<Date>get(User_.expireOn), this.endDayDateHour((Date)line.getValue()));
	    		predicateList.add(pred);    		
	    	}
	    	
	    	
	   		if( line.getKey().toString() == "active"){ 
	    		pred = cb.equal(junction.<Boolean>get(User_.active), (Boolean)line.getValue());
	    		predicateList.add(pred);    		
	       	}
	    }
	    
	    Predicate[] predicates = new Predicate[predicateList.size()];
	    predicateList.toArray(predicates);
	    cq.where(predicates);
        
	    return super.getEntityManager().createQuery(cq).getResultList();			
		
		
	}

}
